using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace HandyIpc
{
    internal static class TypeExtensions
    {
        internal static string GetDefaultKey(this Type interfaceType)
        {
            if (interfaceType.IsGenericType)
            {
                interfaceType = interfaceType.GetGenericTypeDefinition();
            }

            using var sha256 = new SHA256CryptoServiceProvider();
            byte[] buffer = Encoding.UTF8.GetBytes(interfaceType.AssemblyQualifiedName!);
            byte[] sha256Bytes = sha256.ComputeHash(buffer);

            return string.Concat(sha256Bytes.Select(item => item.ToString("x")));
        }

        internal static Type GetClientType(this Type interfaceType)
        {
            return GetAutoGeneratedType(interfaceType, "ClientProxy");
        }

        internal static Type GetDispatcherType(this Type interfaceType)
        {
            return GetAutoGeneratedType(interfaceType, "Dispatcher");
        }

        internal static Type GetServerProxyType(this Type interfaceType)
        {
            return GetAutoGeneratedType(interfaceType, "ServerProxy");
        }

        private static Type GetAutoGeneratedType(Type interfaceType, string category)
        {
            string typeName;
            string prefix = category;

            if (interfaceType.IsNested)
            {
                string className = $"{prefix}{interfaceType.DeclaringType!.Name}{interfaceType.Name}";
                typeName = interfaceType.AssemblyQualifiedName!.Replace(
                    $"{interfaceType.DeclaringType.FullName}+{interfaceType.Name}",
                    $"{interfaceType.Namespace}.{className}");
            }
            else
            {
                string className = $"{prefix}{interfaceType.Name}";

                if (interfaceType.Namespace == null)
                {
                    className = $"{className}.{className}";
                }

                typeName = interfaceType.AssemblyQualifiedName!.Replace(interfaceType.Name, className);
            }

            return Type.GetType(typeName) ??
                   throw new InvalidOperationException($"{interfaceType.Name} doesn't look like a Ipc interface. ");
        }
    }
}
